#include "db_manager.h"
#include "db_schema.h"
#include "logger.h"
#include <stdlib.h>
#include <string.h>

int db_manager_init(db_manager_t *db_mgr, const char *db_path) {
    if (!db_mgr || !db_path) {
        return ERROR_INVALID_PARAM;
    }

    int rc = sqlite3_open(db_path, &db_mgr->db);
    if (rc != SQLITE_OK) {
        LOG_ERROR("Can't open database: %s", sqlite3_errmsg(db_mgr->db));
        sqlite3_close(db_mgr->db);
        return ERROR_DB_OPERATION;
    }

    // 初始化互斥锁
    if (pthread_mutex_init(&db_mgr->mutex, NULL) != 0) {
        sqlite3_close(db_mgr->db);
        return ERROR_THREAD_CREATE;
    }

    db_mgr->db_path = strdup(db_path);
    db_mgr->initialized = true;

    // 初始化数据库模式
    if (db_schema_init(db_mgr->db) != SUCCESS) {
        LOG_ERROR("Failed to initialize database schema");
        db_manager_close(db_mgr);
        return ERROR_DB_OPERATION;
    }

    // 启用外键约束和WAL模式以提高性能
    db_manager_execute(db_mgr, "PRAGMA foreign_keys = ON;", NULL, NULL);
    db_manager_execute(db_mgr, "PRAGMA journal_mode = WAL;", NULL, NULL);
    db_manager_execute(db_mgr, "PRAGMA synchronous = NORMAL;", NULL, NULL);

    LOG_INFO("Database initialized successfully: %s", db_path);
    return SUCCESS;
}

int db_manager_close(db_manager_t *db_mgr) {
    if (!db_mgr || !db_mgr->initialized) {
        return ERROR_DB_NOT_INIT;
    }

    pthread_mutex_lock(&db_mgr->mutex);

    if (db_mgr->db) {
        sqlite3_close(db_mgr->db);
        db_mgr->db = NULL;
    }

    if (db_mgr->db_path) {
        free(db_mgr->db_path);
        db_mgr->db_path = NULL;
    }

    db_mgr->initialized = false;

    pthread_mutex_unlock(&db_mgr->mutex);
    pthread_mutex_destroy(&db_mgr->mutex);

    return SUCCESS;
}

int db_manager_execute(db_manager_t *db_mgr, const char *sql,
                       int (*callback)(void*, int, char**, char**),
                       void *data) {
    if (!db_mgr || !db_mgr->initialized || !sql) {
        return ERROR_INVALID_PARAM;
    }

    pthread_mutex_lock(&db_mgr->mutex);

    char *err_msg = NULL;
    int rc = sqlite3_exec(db_mgr->db, sql, callback, data, &err_msg);

    if (rc != SQLITE_OK) {
        LOG_ERROR("SQL error: %s", err_msg);
        sqlite3_free(err_msg);
        pthread_mutex_unlock(&db_mgr->mutex);
        return ERROR_DB_OPERATION;
    }

    pthread_mutex_unlock(&db_mgr->mutex);
    return SUCCESS;
}

int db_manager_execute_transaction(db_manager_t *db_mgr,
                                   int (*transaction_fn)(sqlite3*, void*),
                                   void *data) {
    if (!db_mgr || !db_mgr->initialized || !transaction_fn) {
        return ERROR_INVALID_PARAM;
    }

    pthread_mutex_lock(&db_mgr->mutex);

    int rc = transaction_fn(db_mgr->db, data);

    pthread_mutex_unlock(&db_mgr->mutex);

    return rc == SQLITE_OK ? SUCCESS : ERROR_DB_OPERATION;
}

// 配置表操作
int db_config_set(db_manager_t *db_mgr, const char *key, const char *value) {
    if (!db_mgr || !key || !value) {
        return ERROR_INVALID_PARAM;
    }

    char *sql = sqlite3_mprintf(
        "INSERT OR REPLACE INTO config (key, value, type, updated_at) "
        "VALUES (%Q, %Q, 'string', strftime('%s','now'));",
        key, value
        );

    int rc = db_manager_execute(db_mgr, sql, NULL, NULL);
    sqlite3_free(sql);

    return rc;
}

char *db_config_get(db_manager_t *db_mgr, const char *key) {
    if (!db_mgr || !key) {
        return NULL;
    }

    char *sql = sqlite3_mprintf("SELECT value FROM config WHERE key = %Q;", key);
    char *result = NULL;

    int callback(void *data, int argc, char **argv, char **col_names) {
        if (argc > 0 && argv[0]) {
            *(char**)data = strdup(argv[0]);
        }
        return 0;
    }

    db_manager_execute(db_mgr, sql, callback, &result);
    sqlite3_free(sql);

    return result;
}

json_t *db_config_get_json(db_manager_t *db_mgr, const char *key) {
    char *value_str = db_config_get(db_mgr, key);
    if (!value_str) {
        return NULL;
    }

    json_error_t error;
    json_t *result = json_loads(value_str, 0, &error);
    free(value_str);

    return result;
}

// 数据池表操作
int db_datapool_set(db_manager_t *db_mgr, const char *key, json_t *value) {
    if (!db_mgr || !key || !value) {
        return ERROR_INVALID_PARAM;
    }

    char *value_str = json_dumps(value, JSON_COMPACT);
    if (!value_str) {
        return ERROR_JSON_PARSE;
    }

    char *sql = sqlite3_mprintf(
        "INSERT OR REPLACE INTO datapool (key, value, timestamp, updated_at) "
        "VALUES (%Q, %Q, strftime('%s','now'), strftime('%s','now'));",
        key, value_str
        );

    free(value_str);

    int rc = db_manager_execute(db_mgr, sql, NULL, NULL);
    sqlite3_free(sql);

    return rc;
}

json_t *db_datapool_get(db_manager_t *db_mgr, const char *key) {
    if (!db_mgr || !key) {
        return NULL;
    }

    char *sql = sqlite3_mprintf("SELECT value FROM datapool WHERE key = %Q;", key);
    char *value_str = NULL;

    int callback(void *data, int argc, char **argv, char **col_names) {
        if (argc > 0 && argv[0]) {
            *(char**)data = strdup(argv[0]);
        }
        return 0;
    }

    db_manager_execute(db_mgr, sql, callback, &value_str);
    sqlite3_free(sql);

    if (!value_str) {
        return NULL;
    }

    json_error_t error;
    json_t *result = json_loads(value_str, 0, &error);
    free(value_str);

    return result;
}

int db_datapool_get_all(db_manager_t *db_mgr,
                        int (*callback)(void*, const char*, json_t*),
                        void *data) {
    if (!db_mgr || !callback) {
        return ERROR_INVALID_PARAM;
    }

    char *sql = "SELECT key, value FROM datapool;";

    int sql_callback(void *user_data, int argc, char **argv, char **col_names) {
        if (argc >= 2 && argv[0] && argv[1]) {
            json_error_t error;
            json_t *value = json_loads(argv[1], 0, &error);
            if (value) {
                int rc = callback(user_data, argv[0], value);
                json_decref(value);
                return rc;
            }
        }
        return 0;
    }

    return db_manager_execute(db_mgr, sql, sql_callback, data);
}

// 事件日志表操作
int db_event_log(db_manager_t *db_mgr, event_type_t type, const char *source,
                 const char *description, json_t *data) {
    if (!db_mgr || !source || !description) {
        return ERROR_INVALID_PARAM;
    }

    char *data_str = data ? json_dumps(data, JSON_COMPACT) : strdup("null");
    if (!data_str) {
        return ERROR_JSON_PARSE;
    }

    char *sql = sqlite3_mprintf(
        "INSERT INTO event_log (type, source, description, data, created_at) "
        "VALUES (%d, %Q, %Q, %Q, strftime('%s','now'));",
        type, source, description, data_str
        );

    free(data_str);

    int rc = db_manager_execute(db_mgr, sql, NULL, NULL);
    sqlite3_free(sql);

    return rc;
}

// 系统状态表操作
int db_system_status_set(db_manager_t *db_mgr, const char *component,
                         const char *status, json_t *details) {
    if (!db_mgr || !component || !status) {
        return ERROR_INVALID_PARAM;
    }

    char *details_str = details ? json_dumps(details, JSON_COMPACT) : strdup("null");
    if (!details_str) {
        return ERROR_JSON_PARSE;
    }

    char *sql = sqlite3_mprintf(
        "INSERT OR REPLACE INTO system_status (component, status, details, updated_at) "
        "VALUES (%Q, %Q, %Q, strftime('%s','now'));",
        component, status, details_str
        );

    free(details_str);

    int rc = db_manager_execute(db_mgr, sql, NULL, NULL);
    sqlite3_free(sql);

    return rc;
}

json_t *db_system_status_get(db_manager_t *db_mgr, const char *component) {
    if (!db_mgr || !component) {
        return NULL;
    }

    char *sql = sqlite3_mprintf(
        "SELECT status, details FROM system_status WHERE component = %Q;",
        component
        );

    struct {
        char *status;
        char *details;
    } result = {0};

    int callback(void *data, int argc, char **argv, char **col_names) {
        if (argc >= 2 && argv[0] && argv[1]) {
            struct { char *status; char *details; } *r = data;
            r->status = strdup(argv[0]);
            r->details = strdup(argv[1]);
        }
        return 0;
    }

    db_manager_execute(db_mgr, sql, callback, &result);
    sqlite3_free(sql);

    if (!result.status) {
        return NULL;
    }

    json_t *json_result = json_object();
    json_object_set_new(json_result, "status", json_string(result.status));

    json_error_t error;
    json_t *details = json_loads(result.details, 0, &error);
    json_object_set_new(json_result, "details", details ? details : json_null());

    free(result.status);
    free(result.details);

    return json_result;
}
